package com.jy.oms.framework.asyn.task.handler;

import com.jy.oms.framework.asyn.task.core.ExecutorConfig;
import com.jy.oms.framework.asyn.task.core.ExecutorContext;
import com.jy.oms.framework.asyn.task.core.ExecutorFailoverConfig;
import com.jy.oms.framework.asyn.task.exception.TaskConfigException;
import com.jy.oms.framework.asyn.task.model.TaskGroup;
import com.jy.oms.framework.asyn.task.model.TaskHandlerWrapper;
import com.jy.oms.framework.asyn.task.model.strategy.ExecuteStrategyObj;
import com.jy.oms.framework.asyn.task.model.strategy.LimiterExecuteStrategy;
import com.jy.oms.framework.asyn.task.util.ExecuteStrategyUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * 任务处理器管理器
 *
 * @author liuquan
 */
@Service
public class TaskHandlerManager implements ITaskHandlerManager {
    private ConcurrentMap<String/**任务编码*/, TaskHandlerWrapper> taskHandlerMap = new ConcurrentHashMap<>();

    @Override
    public void registTaskHandler(String taskCode, TaskHandlerWrapper taskHandler) {
        ExecutorConfig executorConfig = ExecutorContext.getExecutorConfig();
        if (executorConfig == null) {
            return;
        }

        String taskGroup = ExecuteStrategyUtil.getTaskGroup(taskHandler);
        ExecuteStrategyObj executeStrategy = taskHandler.getExecuteStrategy();
        taskHandler.setTaskGroup(new TaskGroup(taskGroup, executeStrategy.getTaskExecuteStrategy(), taskHandler.getTaskQueue()));
        taskHandler.setNeedRateLimit(executeStrategy instanceof LimiterExecuteStrategy);
        if (StringUtils.isBlank(executeStrategy.getTaskGroupDbQueueName())) {
            executeStrategy.setTaskGroupDbQueueName("");
        }
        this.checkExecutorFailoverConfig(taskHandler, taskGroup);

        taskHandlerMap.put(taskCode, taskHandler);
    }

    private void checkExecutorFailoverConfig(TaskHandlerWrapper taskHandler, String taskGroup) {
        ExecutorConfig executorConfig = ExecutorContext.getExecutorConfig();
        ExecutorFailoverConfig executorFailoverConfig = executorConfig.getExecutorFailoverConfig();
        if (executorFailoverConfig == null) {
            return;
        }

        List<String> ableExecuteTaskGroups = executorFailoverConfig.getAbleExecuteTaskGroups();
        if (CollectionUtils.isEmpty(ableExecuteTaskGroups)) {
            return;
        }

        taskHandler.setEnableExecute(ableExecuteTaskGroups.contains(taskGroup));
        taskHandler.setEnableAddTaskIfUnableExecute(executorFailoverConfig.isAbleAddTaskIfUnableExecute());

        String defaultTaskGroupIfUnableExecute = executorFailoverConfig.getDefaultTaskGroupIfUnableExecute();
        if (StringUtils.isNotBlank(defaultTaskGroupIfUnableExecute)) {
            boolean exist = ableExecuteTaskGroups.contains(defaultTaskGroupIfUnableExecute);
            if (!exist) {
                String groups = ableExecuteTaskGroups.stream().collect(Collectors.joining(","));
                throw new TaskConfigException("defaultTaskGroupIfUnableExecute设置不合法，不在可执行任务组[" + groups + "]里");
            }
        } else {
            taskHandler.setDefaultTaskGroupIfUnableExecute(ableExecuteTaskGroups.get(0));
        }
    }

    @Override
    public TaskHandlerWrapper loadTaskHandler(String taskCode) {
        return taskHandlerMap.get(taskCode);
    }

    @Override
    public Map<TaskGroup, List<TaskHandlerWrapper>> loadAllExecutableTaskHandler() {
        ExecutorConfig executorConfig = ExecutorContext.getExecutorConfig();
        if (executorConfig == null) {
            return Collections.emptyMap();
        }
        ExecutorFailoverConfig executorFailoverConfig = executorConfig.getExecutorFailoverConfig();
        return taskHandlerMap.values().stream()
                .filter(task -> {
                    if (executorFailoverConfig != null && CollectionUtils.isNotEmpty(executorFailoverConfig.getAbleExecuteTaskGroups())) {
                        return executorFailoverConfig.getAbleExecuteTaskGroups().contains(task.getTaskGroup().getGroup());
                    }
                    return true;
                })
                .collect(Collectors.groupingBy(TaskHandlerWrapper::getTaskGroup));
    }

    @Override
    public int getExecutableTaskGroupNum() {
        return this.loadAllExecutableTaskHandler().size();
    }

}
